##########################################
## Copyright 2012-2013 Ceruti Francesco
##
##
## This file is part of LiSP (Linux Show Player).
##
## LiSP (Linux Show Player) is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## LiSP (Linux Show Player) is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with LiSP (Linux Show Player).  If not, see <http://www.gnu.org/licenses/>.
##########################################

import re
from PyQt4 import QtGui
from lisp.core.events import Event
from lisp.core.plugin import Plugin
from lisp.utils import utility
from lisp.plugin.sync import master, slave


class Synchronizer(Plugin):

    PLUGIN_NAME = 'Sync'

    NONE = 'NONE'
    SLAVE = 'SLAVE'
    MASTER = 'MASTER'

    PLAY = 'PLAY'
    STOP = 'STOP'
    PAUSE = 'PAUSE'
    SEEK = 'SEEK'  # SEEK:time

    def __init__(self, main):
        self.main = main
        self.mainLayout = main.collectorUi

        self.currentStatus = self.NONE
        self.slave = None
        self.master = None
        self.sysVolume = 0

        self.playAction = Event()
        self.pauseAction = Event()
        self.seekAction = Event()
        self.stopAction = Event()

        # Add Sync menu under "Tools"
        self.syncMenu = QtGui.QMenu('Sync')

        self.setMasterAction = QtGui.QAction('Master', main.mainWindow, triggered=self.setMaster)
        self.setMasterAction.setCheckable(True)
        self.setSlaveAction = QtGui.QAction('Slave', main.mainWindow, triggered=self.setSlave)
        self.setSlaveAction.setCheckable(True)

        self.syncMenu.addAction(self.setMasterAction)
        self.syncMenu.addAction(self.setSlaveAction)

        main.mainWindow.menuTools.addMenu(self.syncMenu)

        main.collector.onMediaAdded.connect(self.connectTrack)
        main.collector.onMediaRemoved.connect(self.disconnectTrack)

    def connectTrack(self, media):
        media.onPlay.connect(self.onPlay)
        media.onStop.connect(self.onStop)
        media.onPause.connect(self.onPause)
        media.onSeek.connect(self.onSeek)

    def disconnectTrack(self, media):
        media.onPlay.disconnect(self.onPlay)
        media.onStop.disconnect(self.onStop)

    def setSlave(self):
        if(self.currentStatus != self.NONE):
            QtGui.QMessageBox.critical(None, 'Error Message', 'A master can not be a slave')
            return

        self.reset()
        if(self.setSlaveAction.isChecked()):
            masterIp = QtGui.QInputDialog.getText(None, 'Input', 'Master IP:', text='127.0.0.1')
            masterPort = QtGui.QInputDialog.getInt(None, 'Input', 'Master Port:', value=5566)
            slavePort = QtGui.QInputDialog.getInt(None, 'Input', 'Salve Port:', value=6655)
            if(masterIp[1] and masterPort[1] and slavePort[1]):
                self.currentStatus = self.SLAVE

                self.slave = slave.Slave((masterIp[0], masterPort[0]), slavePort[0])
                self.slave.syncCmd.connect(self.onSyncCmd)
                self.slave.activeSlave.connect(self.activeSlave)

                self.sysVolume = utility.systemVolume()
                utility.setSystemVolume(0)

    def setMaster(self, setSlave):
        if(self.currentStatus != self.NONE):
            QtGui.QMessageBox.critical(None, 'Error Message', 'A slave can not be a master')
            return

        self.reset()
        if(self.setMasterAction.isChecked()):
            masterPort = QtGui.QInputDialog.getInt(None, 'Input', 'Master Port:', value=5566)
            slavePort = QtGui.QInputDialog.getInt(None, 'Input', 'Salve Port:', value=6655)
            if(masterPort[1] and slavePort[1]):
                self.currentStatus = self.MASTER
                self.master = master.Master(masterPort[0], slavePort[0])

    def reset(self):
        self.currentStatus = self.NONE
        self.slave = None
        self.master = None

    def activeSlave(self):
        self.reset()
        utility.setSystemVolume(self.sysVolume)

    def onSyncCmd(self, cmd):
        cmds = cmd.split(';')
        if(re.findall(self.mainLayout.LAYOUT_CMD_PATTERN, cmds[0]) != []):
            pos = eval(cmds[0])

            cmds[1] = cmds[1].split(':')
            if(cmds[1][0] == self.PLAY):
                self.main.playByPos(pos)
            elif(cmds[1][0] == self.STOP):
                self.main.stopByPos(pos)
            elif(cmds[1][0] == self.PAUSE):
                self.main.pauseByPos(pos)
            elif(cmds[1][0] == self.SEEK):
                self.main.seekByPos(pos, int(cmds[1][1]))

    def onPause(self, media):
        if(self.currentStatus == self.MASTER):
            cmd = str(media.conf['pos']) + ';' + self.PAUSE
            self.master.sendAction(cmd)

    def onPlay(self, media):
        if(self.currentStatus == self.MASTER):
            cmd = str(media.conf['pos']) + ';' + self.PLAY
            self.master.sendAction(cmd)

    def onStop(self, media):
        if(self.currentStatus == self.MASTER):
            cmd = str(media.conf['pos']) + ';' + self.STOP
            self.master.sendAction(cmd)

    def onSeek(self, media, time_ms):
        if(self.currentStatus == self.MASTER):
            cmd = str(media.conf['pos']) + ';' + self.SEEK + ':' + str(time_ms)
            self.master.sendAction(cmd)
